package jk.fox.engine.context;

import jk.fox.annotaion.RpcReference;
import jk.fox.annotaion.RpcService;
import jk.fox.common.exception.runtime.RpcNotSupportServiceException;
import jk.fox.common.payload.container.RpcContainer;
import jk.fox.engine.RpcNodeDefinition;

import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author cuichao
 * @Description: DefaultRpcContext
 * @Date: create in 2020/5/31 22:36
 */
public class DefaultRpcContext extends AbstractAnnotationResolverContext {

    protected final ConcurrentMap<String, RpcNodeDefinition> definitionObjects =  new ConcurrentHashMap<>(32);
    protected final ConcurrentMap<Class, String> definitionTypes =  new ConcurrentHashMap<>(32);
    protected final Lock lock = new ReentrantLock();


    public DefaultRpcContext(RpcContainer container) {
       super(container);
    }

    @Override
    public Object registryService(String bean, Class<?> cls,Object object) {
        putDefinition(bean, cls, true);
        container.addService(bean,object);
        return object;
    }

    @Override
    public Object registryReference(String bean, Class<?> cls,Object object) {
        RpcNodeDefinition definition = putDefinition(bean, cls, false);
        Object proxy = invocation.proxy(definition);
        container.addReference(bean,proxy);
        return proxy;
    }





    @Override
    public Object getService(String key) {
        return container.getService(key);
    }

    @Override
    public Object getReference(String key) {
        return container.getReference(key);
    }


    @Override
    public RpcNodeDefinition getRpcNodeDefinition(String key) {
        return definitionObjects.getOrDefault(key, null);
    }

    @Override
    public RpcNodeDefinition getRpcNodeDefinition(Class<?> cls) {
        String key = definitionTypes.getOrDefault(cls, null);
        if (key == null) {
            return null;
        }
        return getRpcNodeDefinition(key);
    }


    @Override
    public Map<String, RpcNodeDefinition> rpcNodeDefinitions() {
        return Collections.unmodifiableMap(definitionObjects);
    }



    protected RpcNodeDefinition putDefinition(String bean, Class<?> cls, boolean isService){
        return putDefinition(bean,cls,isService,null);
    }


    /**
     * 构建Rpc节点注册信息
     * @param bean
     * @param cls
     * @param isService
     * @return
     */
    protected RpcNodeDefinition putDefinition(String bean, Class<?> cls, boolean isService, Map<String,Object> meta){
        //判断meta 是否为null 或者meta 是否含有ID
        Class<?> target = resolveServiceInterface(cls);
        String id = target.getName();
        if(meta != null && meta.containsKey("id")){
            id = meta.get("id").toString();
        }
        lock.lock();
        try {
            RpcNodeDefinition def = definitionObjects.getOrDefault(id, null);
            //首次加载
            if(def == null){
                def = createDefinition(id,target,meta);
                def.setProvider(isService);
                def.setConsumer(!isService);
                def.setName(bean);
                if(isService && !cls.isInterface() && cls.getAnnotation(RpcService.class) != null){
                    RpcService annotation = cls.getAnnotation(RpcService.class);
                    resolveServiceAnnotation(annotation,def);
                }

                if(!isService && cls.isInterface() && target.getAnnotation(RpcReference.class) != null){
                    RpcReference annotation = target.getAnnotation(RpcReference.class);
                    resolveReferenceAnnotation(annotation,def);
                    buildDefinitionByMeta(def,meta);
                }
                definitionObjects.put(def.getId(),def);
                definitionTypes.put(cls,def.getId());
                return def;
            }
            //是否来自provider
            if(isService){
                def.setProvider(true);
                def.setName(bean);
                if(!cls.isInterface() && cls.getAnnotation(RpcService.class) != null){
                    RpcService annotation = cls.getAnnotation(RpcService.class);
                    resolveServiceAnnotation(annotation,def);
                }
                return def;
            }
            boolean service = def.isProvider();
            def = createDefinition(id,target,meta);
            def.setName(bean);
            def.setConsumer(true);
            def.setProvider(service);
            if(cls.isInterface() && target.getAnnotation(RpcReference.class) != null){
                RpcReference annotation = target.getAnnotation(RpcReference.class);
                resolveReferenceAnnotation(annotation,def);
                buildDefinitionByMeta(def,meta);
            }
            definitionObjects.put(def.getId(),def);
            definitionTypes.put(cls,def.getId());
            return def;
        }finally {
            lock.unlock();
        }
    }

    /**
     * 构建Rpc节点注册信息
     * @param bean
     * @param target
     * @return
     */
    protected RpcNodeDefinition createDefinition(String bean , Class target, Map<String,Object> meta){
        RpcNodeDefinition definition = new RpcNodeDefinition(bean,target);
        return definition;
    }

    private void buildDefinitionByMeta(RpcNodeDefinition definition, Map<String,Object> meta){
       if(meta == null){
            return;
       }

       if(meta.containsKey("id") ){
           String id = meta.get("id").toString();
           if(!"".equals(id.trim())){
               definition.setId(id);
           }
       }

       if(meta.containsKey("retires")){
           Integer retires =  (Integer)meta.get("retires");
           if(retires != null && retires > 0){
               definition.setMaxRetires(retires);
           }
       }

       if(meta.containsKey("timeout")){
           Long timeout = (Long) meta.get("timeout");
           if(timeout != null && timeout > 0){
               definition.setTimeoutMS(timeout);
           }
       }

       if(meta.containsKey("retry")){
           Boolean retry = (Boolean) meta.get("retry");
           if(retry != null){
               definition.setEnableRetry(retry);
           }
       }

    }




    protected Class<?> resolveServiceInterface(Class<?> target){
        if(target.isInterface()){
            return target;
        }
        Class<?>[] interfaces = target.getInterfaces();
        if(interfaces == null || interfaces.length == 0){
            throw new RpcNotSupportServiceException(String.format("%s must be implements interface as a rpc", target.getName()));
        }
        return interfaces[0];
    }
}
